
/**
 * AppleIIGo
 * MMU (Memory Management Unit) class
 * (C) 2008 by Marc S. Ressl (mressl@umich.edu)
 * Released under the GPL
 */

#include "Motherboard.h"

#ifndef MMU_H
#define MMU_H

typedef enum {
	MMUTYPE_II,
	MMUTYPE_IIE,
	MMUTYPE_IIC,
	MMUTYPE_IICPLUS,
	MMUTYPE_IIGS
};

#define PAGE_BYTENUM		0x100
#define BANK_BYTENUM		0x10000

#define OFFSET_ZEROPAGE		0x0000
#define OFFSET_RAM1			0x0200
#define OFFSET_TEXT1		0x0400
#define OFFSET_TEXT2		0x0800
#define OFFSET_RAM2			0x0c00
#define OFFSET_HIRES1		0x2000
#define OFFSET_HIRES2		0x4000
#define OFFSET_RAM3			0x6000
#define OFFSET_IO			0xc000
#define OFFSET_LCBANK1		0xc000
#define OFFSET_LCBANK2		0xd000
#define OFFSET_LCHIGH		0xe000
#define OFFSET_FLOATINGBUS	0x80000000

#define ADDRESSSPACE_BYTENUM	0x1000000
#define ADDRESSSPACE_PAGENUM	(ADDRESSSPACE_BYTENUM >> 8)
#define ADDRESSSPACE_BANKNUM	(ADDRESSSPACE_PAGENUM >> 8)

#define SHADOWMEMORY_MAIN			0x00000
#define SHADOWMEMORY_AUX			0x10000
#define SHADOWMEMORY_VIDEOTERM		0x20000
#define SHADOWMEMORY_FLOATINGBUS	0x20800
#define SHADOWMEMORY_END			0x20900

#define SHADOW_TEXT1INH		(1 << 0)
#define SHADOW_HIRES1INH	(1 << 1)
#define SHADOW_HIRES2INH	(1 << 2)
#define SHADOW_SHIRESINH	(1 << 3)
#define SHADOW_AUXHIRESINH	(1 << 4)
#define SHADOW_TEXT2INH		(1 << 5)
#define SHADOW_IOLCINH		(1 << 6)

#define STATE_INTCXROM		(1 << 0)
#define STATE_ROMBANK		(1 << 1)
#define STATE_LCBNK2		(1 << 2)
#define STATE_RDROM			(1 << 3)
#define STATE_RAMWRT		(1 << 4)
#define STATE_RAMRD			(1 << 5)
#define STATE_PAGE2			(1 << 6)
#define STATE_ALTZP			(1 << 7)

class MMU : public Device {
public:
	MMU(class Motherboard * motherboard, UINT32 mmuType);

	void onDevicesConnected();
	void onMemoryRequested();
	void onMemoryAllocated();
	void onResetAsserted(bool isRestart);
	
	void setLanguageCardBank2(bool value);
	bool isLanguageCardBank2();
	void enableLanguageCardRead(bool value);
	bool isLanguageCardReadEnabled();
	void enableLanguageCardWrite(bool value);
	bool isLanguageCardWriteEnabled();
	
	void setPage2(bool value);
	bool isPage2();
	void setHires(bool value);
	bool isHires();
	void set80Store(bool value);
	bool is80Store();
	void setAuxRead(bool value);
	bool isAuxRead();
	void setAuxWrite(bool value);
	bool isAuxWrite();
	void setAuxZeropage(bool value);
	bool isAuxZeropage();
	void setRomInternal(bool value);
	bool isRomInternal();
	
	void setRomBank2(bool value);
	bool isRomBank2();
	
	void setStateRegister(UINT8 value);
	UINT8 getStateRegister();
	void setShadowAllBanks(bool value);
	bool isShadowAllBanks();
	void setShadowBankLatchEnabled(bool value);
	bool isShadowBankLatchEnabled();
	void setShadowRegister(UINT8 value);
	UINT8 getShadowRegister();
	void setDmaBank(UINT8 value);
	UINT8 getDmaBank();
	
	void setIsVideoModifiedMap(UINT8 * isVideoModifiedMap);
	
	void writeMemory(UINT32 address, UINT8 value);
	UINT8 readMemory(UINT32 address);
	UINT8 readMemoryDirect(UINT32 address);
	
	void setMainMemory(UINT32 mainMemoryOffset, UINT32 mainMemoryByteNum);
	void setRom(UINT32 romOffset, UINT32 romBank1Offset,
				UINT32 romByteNum);
	void setLanguageCardMemory(UINT32 languageCardOffset);
	void setAuxMemory(UINT32 auxMemoryOffset, bool isAuxBank0);
	void setShadowMemory(UINT32 shadowMemoryOffset);
	
private:
	UINT32 mmuType;
	
	class IOU * iou;
	class Memory * memory;
	
	bool isLanguageCardBank2Value;
	bool isLanguageCardReadEnabledValue;
	bool isLanguageCardWriteEnabledValue;
	
	bool isPage2Value;
	bool isHiresValue;
	bool is80StoreValue;
	bool isAuxReadValue;
	bool isAuxWriteValue;
	bool isAuxZeropageValue;
	bool isRomInternalValue;
	bool isRomBank2Value;
	
	bool isShadowAllBanksValue;
	bool isShadowBankLatchEnabledValue;
	UINT8 shadowRegister;
	UINT8 dmaBankRegister;
	
	UINT32 floatingBusReadOffset;
	UINT32 floatingBusWriteOffset;
	UINT32 mainMemoryOffset;
	UINT32 mainMemoryByteNum;
	UINT32 romBank1Offset;
	UINT32 romBank2Offset;
	UINT32 languageCardOffset;
	UINT32 auxMemoryOffset;
	bool isAuxMemoryBank0ShadowInhibited;
	UINT32 shadowMemoryOffset;
	
	UINT8 * memoryPool;
	UINT8 * shadowMemory;
	UINT8 * isVideoModifiedMap;
	bool * isVideoModified;
	
	UINT8 isIoAccess[ADDRESSSPACE_PAGENUM];
	SINT32 memoryMapRead[ADDRESSSPACE_PAGENUM];
	SINT32 memoryMapWrite[ADDRESSSPACE_PAGENUM];
	SINT32 shadowMap[ADDRESSSPACE_PAGENUM];
	
	void initLanguageCard();
	
	UINT32 getMainMemoryOffset(bool isAux);
	SINT32 getValidPage(UINT32 pageNum);
	UINT32 getLanguageCardOffset();
	UINT32 getRomBankOffset();
	
	void mapMainMemory();
	void mapIo();
	void mapLanguageCard();
	void mapShadow(bool isUpdateAllBanks);
	
	void mapIoRange(SINT32 pageStart, SINT32 pageEnd, bool isIoInhibited);
	void mapMemoryRange(SINT32 pageStart, SINT32 pageEnd, 
		UINT32 offsetRead, UINT32 offsetWrite);
	void mapShadowRange(SINT32 pageStart, SINT32 pageEnd,
						bool isShadowingInhibited, bool isShadowBank2);
};

#endif
